#ifndef _FUNCTION_H_
#define _FUNCTION_H_

#include <map>
#include <ctime>
#include <vector>
#include <string>
#include <memory>
#include <sys/time.h>
#include <opencv2/opencv.hpp> 
#include "profile.h"
#include "data.h"
#include "executor.h"
#include "queue.hpp" 

namespace sp{

class Profile;
class Executor;

/*
    所有方法的基类
*/
class Function{
protected:
    short id;                 // id,唯一标识
    std::string name;         // Function的名字 - Function的标识
    std::string class_name;   // Function class name
    int batch_size;           // batch大小
    Executor* executor;       // Executor指针
    bool Python_Function;     // 是不是Python Function
    bool Gpu_Function;        // 是不是GPU Function
    bool Request_Group_Function; // 是不是请组Function，如果是接收时需要接收Empty Data，而不是直接向下游转发。
    bool Flow_Split_Function; // 是不是流分Function，如果是流分Function的话，传输到队列时按照Data的flow_id进行分别传送。
    bool Separate_Function;   // 是不是独立的分离Function
    uint8_t type;             // Function类型，gather，scatter，normal
    std::vector<BlockingQueue<Data*>*> pre_Qs;    // Function对应的输入队列集合
    std::vector<BlockingQueue<Data*>*> next_Qs;   // Function对应的输出队列集合
    std::vector<std::vector<Data*>> recv_buffer;  // 接收数据的缓冲区，第一层代表batch_size，第二层代表队列数。
    std::vector<std::pair<std::vector<uint8_t>, uint8_t>> data_type_support; // Function支持的子类类型，需要子类进行重写。
    std::pair<std::vector<uint8_t>, uint8_t> data_type_current;  // 当前的数据类型。
    bool is_end;              // 判断function是否结束
    int cnt;                  // 第几轮循环
    // 子类构造函数的存储，Function也作为工厂类用于动态创建子类。
    static std::map<std::string, std::function<Function*(std::vector<std::string>)>> classes_map;
    static std::map<std::string, std::function<Function*()>> classes_map2;
    static void Register(std::string class_name, std::function<Function*(std::vector<std::string>)> create_function);
    static void Register(std::string class_name, std::function<Function*()> create_function);
public:
    // 主进程方法
    Function();
    virtual ~Function();
    // 设置属性
    std::string getName();
    std::string getClassName();
    short getId();
    void setId(short id);
    int getCnt();
    void setBatchSize(int batch_size);
    void bindQueues(std::vector<BlockingQueue<Data*>*> pre_Qs, std::vector<BlockingQueue<Data*>*> next_Qs);
    void bindExecutor(Executor* executor);
    void addToPreQs(BlockingQueue<Data*>* q);
    void addToNextQs(BlockingQueue<Data*>* q);
    void clearPreQs();
    void clearNextQs();
    std::vector<BlockingQueue<Data*>*> getPreQs();
    std::vector<BlockingQueue<Data*>*> getNextQs();
    void setPreQs(std::vector<BlockingQueue<Data*>*> pre_Qs);
    void setNextQs(std::vector<BlockingQueue<Data*>*> next_Qs);
    // 执行时相关
    bool recvFromQueues(std::vector<std::vector<Data*>>& data);
    void sendToQueues(std::vector<Data*>& data);
    void handle(std::vector<std::vector<Data*>>& data_input, std::vector<Data*>& data_output);
    // 接口，继承的子Function必须实现
    virtual void start() = 0;           // Function开始运行时会调用一次 
    virtual bool waitForResource() = 0; // 每次接收时会进行判断，获取资源，满足资源条件会继续运行。
    virtual void process(std::vector<std::vector<Data*>>& data_input, std::vector<Data*>& data_output) = 0; // 每次循环都会运行，进行数据处理
    virtual bool releaseResource() = 0; // 每次发送后进行资源的释放。
    virtual void finish() = 0;          // Function结束运行时会调用一次
    virtual bool process();             // 分离方法需要继承
    // 拷贝
    virtual void defaultCopy(Function* other);
    virtual void copy(Function* other) = 0;
    // 判断
    bool isPythonFunction();
    bool isGpuFunction();
    bool isHeadFunction();
    bool isTailFunction();
    bool isSeparateFunction();
    bool isEnd();
    // 检查输入队列和输出队列的类型，是否符合类型，同时给data_type_current进行赋值
    void printSupportTypeMsg();
    void printCurrentTypeMsg();
    std::vector<std::pair<std::vector<uint8_t>, uint8_t>> getDataTypeSupport();
    void setDataTypeCurrent(int flag, uint8_t type);
    void check();
    // 动态创建Function
    static Function* Create(std::string class_name, std::vector<std::string> params);
    static Function* Create(std::string class_name);
    // 运行方法
    void run();
};

class PythonFunction: virtual public Function{
protected:
    /** Python 环境相关 **/
    std::string pModulePath;         // 对应的python文件路径
    std::string pModuleHomePath;     // 对应的python仓库Home目录
    std::string pModuleName;         // 对应的python文件模块名
    std::string pClassName;          // 对应的python类名
    std::vector<std::string> args;   // 类的初始化参数
    PyObject* pModule;               // Module对象
    PyObject* pDict;                 // pModule的属性字典
    PyObject* pClass;                // 目标类
    PyObject* pConstruct;            // 目标类的构造函数 
    PyObject* pInstance;             // 目标类的一个实例
    PyObject* pArgs;                 // 函数参数
    PyObject* pReturn;               // 函数返回值
    std::vector<Data*> data_ins;     // 用于记录GATHER型function convertToCpp时的data_ins, 需要复制data，并自己管理内存。
    Data* parsePyObj(Data* data_input, PyObject* obj); // 解释PyObject放入Data,只能解释基本类型，无法解释列表类型,data_input需是对应的输入，提供头部的参考信息。
    Data* parsePyObj(Data* data_input, PyObject* obj, int i);
    Data* parsePyObj(Data* data_input, PyObject* obj, int i, int j);
    Data* parsePyObj(std::vector<Data*> data_input, PyObject* obj);
    Data* to_list(Data* data, std::vector<Data*> data_vec);
    // default
    void defaultStart();   // pythonFunction关于start函数的默认实现
    void defaultFinish();  // pythonFunction关于finish函数的默认实现
    PyObject* convertToPython(std::vector<std::vector<Data*>>& data_input);
    void convertToCpp(PyObject* data, std::vector<std::vector<Data*>>& data_input, std::vector<Data*>& data_output, int linkPos);
public:
    PythonFunction();
    PythonFunction(std::string pModulePath, std::string pModuleHomePath, std::string pModuleName, std::string pClassName, std::vector<std::string> args);
    virtual ~PythonFunction();
};

class GpuFunction: virtual public Function{
protected:
    /*
        GPU显存的布局：
        有个显存管理器，负责管理哪些stream是空闲的，哪些stream正在被使用，而且要面向整个声明周期，面向整个进程可见。
    */
    short occuStreamId;    // 占用着的stream id
    short targetStreamId;  // 获取到的待使用stream id
    void setOccuStreamIdByDataInput(std::vector<std::vector<Data*>>& data_input); // 通过data_input得到occStreamId
    bool defaultWaitForResource(); // 等待资源就绪
    bool defaultReleaseResource(); // 释放资源
public:
    GpuFunction();
    virtual ~GpuFunction();
};

/**
 * @brief 方法，提供给api
 * 
 */

void check(Function& a, Function& b);
void check(Function& a, Function& b);
void linkFunctions(Function& a, Function& b);
void linkFunctions(Function* a, Function* b);

};
#endif